package org.example.Controller;

import org.example.Event.BasicEvent;
import org.example.Event.listener.BaseListener;
import org.example.Event.EventManager;
import org.example.Forms.IForm;
import org.example.Forms.MainForm;
import org.example.Forms.testForm;
import org.example.Tool.IIdentified;
import org.example.Tool.Idtool;
import org.example.dataHandle.TaskRecord;

import javax.swing.tree.TreeNode;
import javax.xml.transform.Source;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function;

public class FormManagerNode implements TreeNode, IIdentified {
    private final int id;
    protected FormManagerNode parent;

    protected ArrayList<FormManagerNode> nodes;

    protected IForm form;

    protected FormBuilder builder = new FormBuilder();

    protected boolean isRun = false;

    //只有mainForm调用
    public FormManagerNode() {
        nodes = new ArrayList<>();
        nodes.add(this);
        id = Idtool.distributeId();
    }

    public FormManagerNode(Function<FormManagerNode, IForm> factory, FormManagerNode parent) {
        this();
        this.builder.setFactory(factory);
        this.parent = parent;
        parent.addNode(this);

        int Num = parent.getIndex(this);
        if (Num == -1)
            throw new RuntimeException("failed to initialize FormManagerNode " + this);

        EventManager.addListener(e -> {
            if(form != null
                    && e instanceof BasicEvent
                    && ((BasicEvent) e).type == BasicEvent.EventType.FormClosing
                    && Objects.equals(((Source) e.getSource()).getSystemId(), form.getSystemId())){
                FormManagerNode.this.stopTask();
            }
        });
    }

    //Used only by mainForm when from extern code
    public void init(IForm main) {
        this.form = main;
    }

    public void runTask() {
        this.runTask(FormRunType.RUN_ON_THIS_THREAD);
    }

    private void createForm(){
        builder.build();
        form.show();
    }

    public void runTask(FormRunType type) {
        this.isRun = true;
        if (this.form instanceof MainForm) {
            this.form.show();
            return;
        }
        switch (type) {
            case RUN_ON_THIS_THREAD -> {
                createForm();
                break;
            }
            case RUN_ON_ANOTHER_THREAD -> {
                Thread thread = new Thread(new RunForm());
                thread.start();
                break;
            }
        }
    }

    //Received ExitMessage
    public void stopTask() {
        this.isRun = false;
    }

    public void addNode(FormManagerNode Node) {
        this.nodes.add(Node);
    }

    @Override
    public TreeNode getChildAt(int childIndex) {
        return nodes.get(childIndex + 1);
    }

    @Override
    public int getChildCount() {
        return nodes.size() - 1;
    }

    @Override
    public TreeNode getParent() {
        return parent;
    }

    @Override
    public int getIndex(TreeNode node) {
        if (node instanceof FormManagerNode)
            return this.nodes.indexOf(node);
        else
            throw new RuntimeException("unexpected pram for FormManagerNode.getIndex()");
    }

    @Override
    public boolean getAllowsChildren() {
        return false;
    }

    @Override
    public boolean isLeaf() {
        return nodes.size() <= 1;
    }

    //not on using
    @Override
    public Enumeration<? extends TreeNode> children() {
        if(nodes.size() == 1)
            return null;
        return new Enumeration<FormManagerNode>() {
            private final Iterator<FormManagerNode> iterator;
            {
                Iterator<FormManagerNode> temp = FormManagerNode.this.nodes.iterator();
                temp.next();
                if(temp.hasNext())
                    iterator = temp;
                else
                    throw new RuntimeException(FormManagerNode.this + "failed to get children");
            }
            @Override
            public boolean hasMoreElements() {
                return iterator.hasNext();
            }

            @Override
            public FormManagerNode nextElement() {
                return iterator.next();
            }
        };
    }

    public boolean getIsRun(){
        return this.isRun;
    }

    @Override
    public int getId() {
        return id;
    }

    public class RunForm implements Runnable {

        public RunForm(){
        }
        @Override
        public void run() {
            synchronized (FormManagerNode.this) {
               createForm();
            }
            while (isRun) {
                try{
                    Thread.sleep(100);
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                }
            }
        }
    }

    protected class FormBuilder {
        protected Function<FormManagerNode, IForm> factory;

        protected HashMap<Object, BiConsumer<Object,IForm>> set = new HashMap<>();
        public void setFactory(Function<FormManagerNode, IForm> factory) {
            this.factory = factory;
        }

        public void addProperty(Object obj,BiConsumer<Object,IForm> attach_func){
                set.put(obj,attach_func);
        }
        protected void build(){
            form = factory.apply(FormManagerNode.this);
            set.forEach((o,c)->c.accept(o,form));
        }
    }

    public enum FormRunType {
        RUN_ON_THIS_THREAD,
        RUN_ON_ANOTHER_THREAD
    }
}
